﻿using System;
using System.Linq;
using System.Text;
using System.Windows.Threading;
using System.Xml.Linq;
using PengSW.NotifyPropertyChanged;
using PengSW.ObservableCollectionHelper;
using PengSW.TcpService;
using static PengSW.RuntimeLog.RL;
using static PengSW.XmlHelper.XmlLinqHelper;

namespace ProtocolAnalyzer
{
    public class AnalyzeModel : NotifyPropertyChangedObject
    {
        public AnalyzeModel(Dispatcher aDispatcher)
        {
            _Dispatcher = aDispatcher;
        }

        public static Encoding[] Encodings { get; } = new Encoding[] { Encoding.ASCII, Encoding.UTF7, Encoding.UTF8, Encoding.UTF32, Encoding.Unicode, Encoding.Default, Encoding.BigEndianUnicode };

        private Dispatcher _Dispatcher;

        public int ListenPort { get { return _ListenPort; } set { SetValue(ref _ListenPort, value, nameof(ListenPort)); } }
        private int _ListenPort = 10001;

        public ProtocolRule ListenRule { get => _ListenRule; set { SetValue(ref _ListenRule, value, nameof(ListenRule)); } }
        private ProtocolRule _ListenRule;

        public ObservableCollectionEx<ProtocolRule> Rules { get; } = new ObservableCollectionEx<ProtocolRule>();

        #region 序列化

        private const string ConfigFileName = "ProtocolAnalyzer.xml";

        public void Load()
        {
            XDocument aXDocument = XDocument.Load(ConfigFileName);
            ListenPort = aXDocument.Root.GetAttributeValue(nameof(ListenPort), 10001);
            Rules.Clear();
            foreach (XElement aXElement in aXDocument.Root.Elements(nameof(ProtocolRule)))
            {
                ProtocolRule aRule = new ProtocolRule();
                aRule.ReadFromXml(aXElement);
                Rules.Add(aRule);
            }
            int aIndex = aXDocument.Root.GetAttributeValue(nameof(ListenRule), 0);
            ListenRule = (aIndex >= 0 && aIndex < Rules.Count) ? Rules[aIndex] : null;
        }

        public void Save()
        {
            XDocument aXDocument = new XDocument(new XElement("ProtocolAnalyzer",
                CreateXAttribute(nameof(ListenPort), ListenPort),
                CreateXAttribute(nameof(ListenRule), ListenRule != null ? Rules.IndexOf(ListenRule).ToString() : null),
                from r in Rules select r.CreateXElement(nameof(ProtocolRule))));
            aXDocument.Save(ConfigFileName);
        }

        #endregion

        public bool IsListenning => _Listener != null && _Listener.IsListening;
        public bool CanStartListen => !IsListenning && ListenRule != null;
        
        private Listener _Listener;

        #region 用于创建连接的参数

        public string Host { get => _Host; set { SetValue(ref _Host, value, nameof(Host)); } }
        private string _Host = "127.0.0.1";

        public int Port { get => _Port; set { SetValue(ref _Port, value, nameof(Port)); } }
        private int _Port = 10001;

        public ProtocolRule ConnectionRule { get => _ConnectionRule; set { SetValue(ref _ConnectionRule, value, nameof(ConnectionRule)); } }
        private ProtocolRule _ConnectionRule;

        #endregion

        public ObservableCollectionEx<Connection> Connections { get; } = new ObservableCollectionEx<Connection>();
        public Connection CurrentConnection => Connections?.ActiveItem;
        public AnalyzeProtocol CurrentProtocol => CurrentConnection?.Protocol as AnalyzeProtocol;

        public void StartListen()
        {
            _Listener = new Listener("Listener", ListenPort, new AnalyzeProtocolFactory(ListenRule));
            _Listener.BytesFrameReceived += _Listener_BytesFrameReceived;
            _Listener.Clarify += _Listener_Clarify;
            _Listener.Connected += _Listener_Connected;
            _Listener.Disconnected += _Listener_Disconnected;
            _Listener.ObjectFrameReceived += _Listener_ObjectFrameReceived;
            _Listener.Received += _Listener_Received;
            _Listener.TextFrameReceived += _Listener_TextFrameReceived;
            _Listener.StartListen();
            OnPropertyChanged(nameof(IsListenning));
        }

        public void SendTextToCurrentConnection(string aText)
        {
            CurrentProtocol.SendText(aText);
        }

        private void _Listener_TextFrameReceived(Connection aConnection, string aTextFrame)
        {
            L($"收到{aConnection}发来的文本帧：[{aTextFrame}]。");
        }

        private void _Listener_Received(Connection aConnection, byte[] aBytes)
        {
            L($"收到{aConnection}发来的：[{aBytes.BytesToString()}]。");
        }

        private void _Listener_ObjectFrameReceived(Connection aConnection, object aObjectFrame)
        {
            L($"收到{aConnection}发来的对象帧：[{aObjectFrame}]。");
        }

        private void _Listener_Disconnected(Listener aListener, Connection aConnection)
        {
            L($"与{aConnection}的连接已断开。");
            _Dispatcher.Invoke(new Action(() => Connections.Remove(aConnection)));
        }

        private void _Listener_Connected(Listener aListener, Connection aConnection)
        {
            L($"已建立到{aConnection}的连接。");
            _Dispatcher.Invoke(new Action(() => Connections.Add(aConnection)));
        }

        private void _Listener_Clarify(string aInfo, int aLevel)
        {
            L(aInfo, false, true, aLevel);
        }

        private void _Listener_BytesFrameReceived(Connection aConnection, byte[] aBytesFrame)
        {
            L($"收到{aConnection}发来的字节帧：[{aBytesFrame.BytesToString()}]。");
        }

        public void StopListen()
        {
            _Listener.StopListen();
            _Listener = null;
            OnPropertyChanged(nameof(IsListenning));
        }

        public bool CanCreateConnection => !string.IsNullOrWhiteSpace(Host) && ConnectionRule != null;
        public void CreateConnection()
        {
            Connection aConnection = new Connection(new AnalyzeProtocol(ConnectionRule), "AnalyzeConnection");
            aConnection.Connected += OnConnection_Connected;
            aConnection.Disconnected += OnConnection_Disconnected;
            aConnection.TextFrameReceived += OnConnection_TextFrameReceived;
            aConnection.WorkWith(Host, Port);
        }

        private void OnConnection_TextFrameReceived(Connection aConnection, string aTextFrame)
        {
            L($"收到{aConnection}发来的[{aTextFrame}]");
        }

        private void OnConnection_Disconnected(object sender, EventArgs e)
        {
            Connection aConnection = sender as Connection;
            L($"与{aConnection}的连接已断开。");
            _Dispatcher.Invoke(new Action(() => Connections.Remove(aConnection)));
        }

        private void OnConnection_Connected(object sender, EventArgs e)
        {
            Connection aConnection = sender as Connection;
            L($"已建立到{aConnection}的连接。");
            _Dispatcher.Invoke(new Action(() => Connections.Add(aConnection)));
        }
    }
}
